iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0

我們要接續昨天的進度,為首頁新增一個功能,提示即將到期的物品,讓使用者能一眼就看見哪些物品需要注意,避免過期浪費。這個功能將顯示在首頁物品列表的上方,並會根據當前選擇的月份來顯示即將到期的物品。

目標

  • 在首頁的物品列表上方新增一個區塊,提示即將到期的物品。
  • 當使用者切換月份時,該區塊會根據所選月份更新顯示的即將到期物品。
  • 即將到期的物品根據到期日期以不同顏色提示:三天內到期的物品顯示紅色,其他物品顯示黃色。

https://ooorito.com/wp-content/uploads/2024/10/%E7%9B%AE%E6%A8%99%E7%A4%BA%E6%84%8F%E5%9C%96-1.webp

主要實作

實作 ExpiringItemsView

ExpiringItemsView 為負責顯示即將到期物品的區塊,它會根據當前月份即將到期的物品列表進行顯示。如果有到期的物品,列表會顯示物品的名稱及到期日;如果沒有,即顯示一條提示文字告知沒有即將到期的物品。

struct ExpiringItemsView: View {
    @ObservedObject var viewModel: ItemViewModel
    
    var body: some View {
        if viewModel.expiringItems.isEmpty {
            // 如果沒有即將到期的物品,顯示一個簡單的提示
            Text("本月沒有即將到期的物品")
                .font(.subheadline)
                .foregroundColor(.gray)
                .padding(.top, 10)
        } else {
            ScrollView {
                LazyVStack(spacing: 15) {
                    ForEach(viewModel.expiringItems, id: \.id) { item in
                        HStack(spacing: 15) {
                            Image(systemName: "clock.fill")
                                .foregroundColor(daysUntilExpiry(item.expiryDate) <= 3 ? .red : .yellow)
                                .font(.title2)
                            
                            VStack(alignment: .leading, spacing: 5) {
                                Text(item.name)
                                    .font(.headline)
                                    .foregroundColor(.primary)
                                
                                Text("到期日: \(item.expiryDate?.formatted(date: .abbreviated, time: .omitted) ?? "未設定")")
                                    .font(.subheadline)
                                    .foregroundColor(.secondary)
                            }
                            Spacer()
                            
                            Text(item.location.name)
                                .font(.subheadline)
                                .padding(6)
                                .background(Color.blue.opacity(0.2))
                                .foregroundColor(.blue)
                                .cornerRadius(5)
                        }
                        .padding()
                        .background(Color(UIColor.secondarySystemBackground))
                        .cornerRadius(10)
                        .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
                    }
                }
                .padding(.horizontal)
            }
        }
    }
}

而列表不止顯示物品的名稱、到期日和放置地點,還會根據物品的到期日做出不同的顏色提示:三天內到期的物品會顯示紅色圖標,其他物品則會顯示黃色圖標,讓使用者可以一目了然地知道哪些物品需要優先處理。

func daysUntilExpiry(_ expiryDate: Date?) -> Int {
    guard let expiryDate = expiryDate else { return Int.max }
    let currentDate = Date()
    let diffComponents = Calendar.current.dateComponents([.day], from: currentDate, to: expiryDate)
    return diffComponents.day ?? Int.max
}

更新 ViewModel

接著,我們需要在 HomeViewModel 中實作一個屬性 expiringItems,該屬性篩選出所有尚未使用完畢且到期日在當前月份內的物品。

var expiringItems: [Item] {
    let calendar = Calendar.current
    return items.filter { item in
        if let expiryDate = item.expiryDate {
            let itemMonth = calendar.component(.month, from: expiryDate)
            let itemYear = calendar.component(.year, from: expiryDate)
            let selectedMonth = calendar.component(.month, from: selectedDate)
            let selectedYear = calendar.component(.year, from: selectedDate)
                return itemMonth == selectedMonth && itemYear == selectedYear && !(item.isUsedUp)
        }
        return false
    }
}

這裡的 expiringItems 會根據選定的月份篩選即將到期的物品。通過 Calendar 的 .component 方法來比對物品到期日與選擇的月份,從而只顯示當前月份到期的物品。

參考資料:

更新 HomeView

最後,我們需要將 ExpiringItemsView 整合到 HomeView 中,讓它顯示在物品列表的上方。只要 HomeView 的物品資訊發生變化,提示區塊也會根據篩選後的資料自動更新。

struct HomeView: View {
    // 略...
    var body: some View {
        NavigationView {
            ZStack(alignment: .bottomTrailing) {
                
                VStack {
                    ExpiringItemsView(viewModel: viewModel)
                        .frame(height:250)
                    ItemListView(viewModel: viewModel)
                        .frame(maxHeight: .infinity)
                        .frame(maxWidth: .infinity)
                        .onAppear {
                            viewModel.fetchItems()
                    }
                }
            // 略...

總結

今天我們成功在首頁的物品列表上方新增了即將到期物品的提示區塊,並根據到期日提供不同的顏色提示。這個功能幫助使用者更好地管理物品的有效期,避免過期浪費。


上一篇
Day 28: SwiftUI 顯示月份與自定義月份選擇器實作
下一篇
Day 30: 賽後感想
系列文
用 SwiftUI 掌控家庭日用品庫存30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言